#ifndef PRUEBATOOLKIT_H_
#define PRUEBATOOLKIT_H_

#include "Alumno.h"
#include "ClaveAlumno.h"
#include "../RecursoAlmacenamiento.h"
#include "../FabricaRecursos.h"
#include "../funciones.h"
#include "../Excepciones.h"

void cargaMasivaDeDatos(Toolkit::RecursoAlmacenamiento *recurso,
		Toolkit::TipoSerializacion tSerialiazcion,
		const unsigned long int &cantidad)
{

	string nombre = "Alumno Nº";
	unsigned long int DNI = 33000000;
	int padron = 80000;

	Toolkit::Alumno *alumno = new Toolkit::Alumno(padron, DNI, nombre,
			tSerialiazcion);
	Toolkit::ClaveAlumno *clave = new Toolkit::ClaveAlumno(padron,
			tSerialiazcion);

	recurso->setControlUnicidad(false);
	for (unsigned long int i = 0; i < cantidad; i++)
	{
		alumno->setPadron(padron + i);
		alumno->setDNI(DNI + i);
		alumno->setNombre(string(nombre).append(intToStr(i, 4)));
		clave->setPadron(padron + i);

		recurso->guardarDato((*alumno), (*clave));

		delete alumno;
		delete clave;

		alumno = new Toolkit::Alumno(padron, DNI, nombre, tSerialiazcion);
		clave = new Toolkit::ClaveAlumno(padron, tSerialiazcion);

	}

	cout << "termino la carga de datos" << endl;

	recurso->setControlUnicidad(true);

	try
	{
		clave->setPadron(80012);
		recurso->guardarDato((*alumno), (*clave));

		cout << "ANDUVO MAL!! la unicidad" << endl;
	} catch (ClaveDuplicadaException& e)
	{
		cout << "Se controla bien la unicidad" << endl;
	}

	delete alumno;
	delete clave;

}

void recuperacionSimple(Toolkit::RecursoAlmacenamiento *recurso,
		Toolkit::TipoSerializacion tSerializacion)
{

	Toolkit::Alumno jesus(87712, 22115999, "Jesús Olano Jr.", tSerializacion);
	recurso->guardarDato(jesus, Toolkit::ClaveAlumno(jesus.getPadron(),
			tSerializacion));

	Toolkit::Alumno dupont(55555, 33000999, "Marcel Dupont", tSerializacion);
	recurso->guardarDato(dupont, Toolkit::ClaveAlumno(dupont.getPadron(),
			tSerializacion));

	Toolkit::Alumno artigas(11111, 55115999, "Pepe Artigas", tSerializacion);
	recurso->guardarDato(artigas, Toolkit::ClaveAlumno(artigas.getPadron(),
			tSerializacion));

	Toolkit::Alumno aux(0, 33115999, "AUXILIAR", tSerializacion);
	bool recuperado = true;

	recuperado = recurso->recuperarDato(Toolkit::ClaveAlumno(jesus.getPadron(),
			tSerializacion), aux);
	recuperado = ((recuperado) && (aux.getNombre() == jesus.getNombre()));
	recuperado = ((recuperado) && ((aux.getDNI()) == (jesus.getDNI())));

	recuperado = ((recuperado) && (recurso->recuperarDato(Toolkit::ClaveAlumno(
			artigas.getPadron(), tSerializacion), aux)));
	recuperado = ((recuperado) && (aux.getNombre() == artigas.getNombre()));
	recuperado = ((recuperado) && (aux.getDNI() == artigas.getDNI()));

	if (recuperado)
	{
		cout << "Recuperación satisfactoria" << endl;
	}
	else
	{
		cout << "ANDUVO MAL!! la recuperación" << endl;
	}

}

void modificacionSimple(Toolkit::RecursoAlmacenamiento *recurso,
		Toolkit::TipoSerializacion tSerializacion)
{

	Toolkit::Alumno donCarlos(99999, 22115999, "Bien Don Carlos",
			tSerializacion);
	recurso->guardarDato(donCarlos, Toolkit::ClaveAlumno(donCarlos.getPadron(),
			tSerializacion));

	Toolkit::Alumno bilardo(50505, 55115999, "Carlos Salvado Bilardo",
			tSerializacion);
	recurso->guardarDato(bilardo, Toolkit::ClaveAlumno(bilardo.getPadron(),
			tSerializacion));

	//Modifico uno de los datos
	bool modificado = true;
	Toolkit::Alumno auxLectura(0, 0, "", tSerializacion);

	Toolkit::Alumno auxEscritura(bilardo.getPadron(), 565656, "Nuevo Bilardo",
			tSerializacion);
	recurso->actualizarDato(auxEscritura, Toolkit::ClaveAlumno(
			auxEscritura.getPadron(), tSerializacion));

	//verifico que se almacenaron los cambios
	modificado = recurso->recuperarDato(Toolkit::ClaveAlumno(
			bilardo.getPadron(), tSerializacion), auxLectura);
	modificado = ((modificado) && (auxLectura.getNombre()
			== auxEscritura.getNombre()));
	modificado = ((modificado) && ((auxLectura.getDNI())
			== auxEscritura.getDNI()));

	//Modifico uno de el otro
	auxEscritura.setPadron(donCarlos.getPadron());
	auxEscritura.setDNI(11);
	auxEscritura.setNombre("Mal Don Carlos");

	recurso->actualizarDato(auxEscritura, Toolkit::ClaveAlumno(
			auxEscritura.getPadron(), tSerializacion));

	//verifico que se almacenaron los cambios
	modificado = ((modificado) && (recurso->recuperarDato(Toolkit::ClaveAlumno(
			donCarlos.getPadron(), tSerializacion), auxLectura)));
	modificado = ((modificado) && (auxLectura.getNombre()
			== auxEscritura.getNombre()));
	modificado = ((modificado) && ((auxLectura.getDNI())
			== auxEscritura.getDNI()));

	if (modificado)
	{
		cout << "Modificación satisfactoria" << endl;
	}
	else
	{
		cout << "ANDUVO MAL!! la mdificaión" << endl;
	}
}

void eliminacionSimple(Toolkit::RecursoAlmacenamiento *recurso,
		Toolkit::TipoSerializacion tSerializacion)
{

	Toolkit::Alumno
			quiroga(123456, 21115999, "Rolando Quiroga", tSerializacion);
	recurso->guardarDato(quiroga, Toolkit::ClaveAlumno(quiroga.getPadron(),
			tSerializacion));

	Toolkit::Alumno otro(55005, 33088799, "Otro Alumno", tSerializacion);
	recurso->guardarDato(otro, Toolkit::ClaveAlumno(otro.getPadron(),
			tSerializacion));

	bool eliminado = true;

	Toolkit::Alumno auxLectura(0, 0, "", tSerializacion);

	//Elimino un dato
	recurso->eliminarDato(Toolkit::ClaveAlumno(quiroga.getPadron(),
			tSerializacion), auxLectura);

	//verifico que lo devuelve correctamene y que ya no esta en el amacenamiento
	eliminado
			= ((eliminado) && (auxLectura.getNombre() == quiroga.getNombre()));
	eliminado = ((eliminado) && ((auxLectura.getDNI()) == quiroga.getDNI()));
	eliminado = ((eliminado) && (!recurso->recuperarDato(Toolkit::ClaveAlumno(
			quiroga.getPadron(), tSerializacion), auxLectura)));

	//Elimino el otro
	recurso->eliminarDato(
			Toolkit::ClaveAlumno(otro.getPadron(), tSerializacion), auxLectura);

	//verifico que lo devuelve correctamene y que ya no esta en el amacenamiento
	eliminado = ((eliminado) && (auxLectura.getNombre() == otro.getNombre()));
	eliminado = ((eliminado) && ((auxLectura.getDNI()) == otro.getDNI()));
	eliminado = ((eliminado) && (!recurso->recuperarDato(Toolkit::ClaveAlumno(
			otro.getPadron(), tSerializacion), auxLectura)));

	if (eliminado)
	{
		cout << "Eliminación satisfactoria" << endl;
	}
	else
	{
		cout << "ANDUVO MAL!! la eliminación" << endl;
	}

}

void creacionesErroneas()
{
	//hago un par de intenros de crear archivos que no existen o no estan bien nombrados

	bool satisfactorio = true;

	Toolkit::RecursoAlmacenamiento *recurso = NULL;
	try
	{
		recurso = Toolkit::FabricaRecursos::instancia().recuperarRecurso(
				"test/archivos/", "archivoNoExiste", Toolkit::TEXTO);

		satisfactorio = false;
		delete recurso;

	} catch (ArchivoInexistenteException &e)
	{
		if (recurso != NULL)
		{
			delete recurso;
		}
		satisfactorio = true;

	}

	if (satisfactorio)
	{
		cout << "Se chequea bien la creación de recursos";
	}
	else
	{
		cout << "ANDUVO MAL!! la creacion de recursos erroneos" << endl;
	}

}

void eliminacionMasiva(Toolkit::RecursoAlmacenamiento *recurso,
		Toolkit::TipoSerializacion tSerializacion, int padronInicial,
		int padronFinal)
{

	Toolkit::Alumno *alumno = new Toolkit::Alumno(0, 0, "", tSerializacion);
	Toolkit::ClaveAlumno *clave = new Toolkit::ClaveAlumno(0, tSerializacion);

	for (int i = padronInicial; i < padronFinal; i++)
	{
		clave->setPadron(i);
		recurso->eliminarDato((*clave), (*alumno));
	}

	bool encontrado = false;
	for (int i = padronInicial; i < padronFinal; i++)
	{
		clave->setPadron(i);
		encontrado = ((encontrado) || (recurso->recuperarDato((*clave),
				(*alumno))));
	}

	if (!encontrado)
	{
		cout << "Las eliminaciones fueron satisfactorias" << endl;
	}
	else
	{
		cout << "ANDUVO MAL!! las eliminaciones" << endl;
	}

	delete clave;
	delete alumno;

}

void busquedasExistentesRango(Toolkit::RecursoAlmacenamiento *recurso,
		Toolkit::TipoSerializacion tSerializacion, int padronInicial,
		int padronFinal)
{

	bool encontrado = true;
	Toolkit::Alumno *alumno = new Toolkit::Alumno(0, 0, "", tSerializacion);
	Toolkit::ClaveAlumno *clave = new Toolkit::ClaveAlumno(0, tSerializacion);

	for (int i = padronInicial; i < padronFinal; i++)
	{
		clave->setPadron(i);
		encontrado = ((encontrado) && (recurso->recuperarDato((*clave),
				(*alumno))));
		encontrado = ((encontrado) && (alumno->getPadron() == (i)));
	}

	if (encontrado)
	{
		cout << "Las busquedas fueron satisfactorias" << endl;
	}
	else
	{
		cout << "ANDUVO MAL!! la busqueda" << endl;
	}

	delete clave;
	delete alumno;
}

Toolkit::RecursoAlmacenamiento *nuevoArchivo()
{

	return Toolkit::FabricaRecursos::instancia().recursoArchivo(
			"test/archivos/", "archivo", Toolkit::A_BLOQUES, 500,
			Toolkit::HASHING_EXTENSIBLE);
}

Toolkit::RecursoAlmacenamiento *nuevoBuffer()
{

	return Toolkit::FabricaRecursos::instancia().recursoBuffer(
			Toolkit::A_REGISTROS, 55);
}

Toolkit::RecursoAlmacenamiento *nuevoArchivoBSharpTexto()
{

	return Toolkit::FabricaRecursos::instancia().recursoArchivo(
			"test/archivos/", "archivo", Toolkit::A_TEXTO, 50, Toolkit::B_SHARP);
}

Toolkit::RecursoAlmacenamiento *nuevoArchivoBSharpBinario()
{
	return Toolkit::FabricaRecursos::instancia().recursoArchivo(
			"test/archivos/", "archivo", Toolkit::A_BLOQUES, 500,
			Toolkit::B_SHARP);
}

Toolkit::RecursoAlmacenamiento *nuevoDirecto()
{

	return Toolkit::FabricaRecursos::instancia().recursoEscrituraDirecta(
			"test/archivos/", "archivo", Toolkit::A_BLOQUES, 500,
			Toolkit::HASHING_EXTENSIBLE);
}

Toolkit::RecursoAlmacenamiento *nuevoDiferidoBinario()
{

	return Toolkit::FabricaRecursos::instancia().recursoEscrituraDiferida(
			"test/archivos/", "archivo", Toolkit::A_BLOQUES, 500,
			Toolkit::HASHING_EXTENSIBLE, 100);
}

Toolkit::RecursoAlmacenamiento *nuevoDiferidoTexto()
{

	return Toolkit::FabricaRecursos::instancia().recursoEscrituraDiferida(
			"test/archivos/", "archivo", Toolkit::A_TEXTO, 50,
			Toolkit::SIN_INDEXADO, 100);
}

Toolkit::RecursoAlmacenamiento *viejoRecurso(
		Toolkit::TipoSerializacion tSerializacion)
{

	return Toolkit::FabricaRecursos::instancia().recuperarRecurso(
			"test/archivos/", "archivo", tSerializacion);
}

Toolkit::RecursoAlmacenamiento *nuevoBloquesCompresos()
{

	return Toolkit::FabricaRecursos::instancia().recursoEscrituraDirecta(
			"test/archivos/", "archivo", Toolkit::A_BLOQUES_COMPRESOS, 500,
			Toolkit::SIN_INDEXADO);
}

void pruebaAux(Toolkit::RecursoAlmacenamiento *recurso, string nombre,
		Toolkit::TipoSerializacion tSerializacion)
{
	cout << endl << "Comienzan las pruebas de " << nombre << "...." << endl;

	cargaMasivaDeDatos(recurso, tSerializacion, 1500);
	eliminacionMasiva(recurso, tSerializacion, 80300, 80400);

	busquedasExistentesRango(recurso, tSerializacion, 80100, 80200);

	recuperacionSimple(recurso, tSerializacion);
	modificacionSimple(recurso, tSerializacion);
	eliminacionSimple(recurso, tSerializacion);

	cout << "done" << endl;
}

void pruebaReconstruido(Toolkit::RecursoAlmacenamiento *recurso,
		Toolkit::TipoSerializacion tSerializacion)
{

	cout << "Pruebo recuperandolo... " << endl;

	eliminacionMasiva(recurso, tSerializacion, 80500, 80700);
	busquedasExistentesRango(recurso, tSerializacion, 81100, 81200);

	//para chequear que funciona, creo uno, busco y lo elimino

	Toolkit::Alumno viejo(55566, 10015999, "En Recurso Viejo", tSerializacion);
	recurso->guardarDato(viejo, Toolkit::ClaveAlumno(viejo.getPadron(),
			tSerializacion));

	Toolkit::Alumno auxLectura(0, 0, "", tSerializacion);
	bool encontrado = recurso->recuperarDato(Toolkit::ClaveAlumno(
			viejo.getPadron(), tSerializacion), auxLectura);
	encontrado
			= ((encontrado) && (viejo.getNombre() == auxLectura.getNombre()));
	encontrado = ((encontrado) && ((viejo.getDNI()) == (auxLectura.getDNI())));

	recurso->eliminarDato(Toolkit::ClaveAlumno(viejo.getPadron(),
			tSerializacion), auxLectura);
	encontrado
			= ((encontrado) && (viejo.getNombre() == auxLectura.getNombre()));
	encontrado = ((encontrado) && ((viejo.getDNI()) == (auxLectura.getDNI())));
	encontrado = ((encontrado)
			&& (!recurso->recuperarDato(Toolkit::ClaveAlumno(viejo.getPadron(),
					tSerializacion), auxLectura)));

	if (encontrado)
	{
		cout << "Operaciones sobre el recuperado fueron satisfactorias" << endl;
	}
	else
	{
		cout << "ANDUVO MAL!! el recurso recuperado" << endl;
	}

}

void pruebaEspecialCompresion() {
	Toolkit::RecursoAlmacenamiento *recurso = nuevoBloquesCompresos();

	cout << endl << "Comienzan las pruebas de Bloques compresos...." << endl;

	cargaMasivaDeDatos(recurso, Toolkit::BINARIO, 200);
	eliminacionMasiva(recurso, Toolkit::BINARIO, 80050, 80070);

	busquedasExistentesRango(recurso, Toolkit::BINARIO, 80001, 80050);

	recuperacionSimple(recurso, Toolkit::BINARIO);
	modificacionSimple(recurso, Toolkit::BINARIO);
	eliminacionSimple(recurso, Toolkit::BINARIO);

	cout << "done" << endl;

	delete recurso;

	recurso = viejoRecurso(Toolkit::BINARIO);

	cout << "Pruebo recuperandolo... " << endl;

	eliminacionMasiva(recurso, Toolkit::BINARIO, 80100, 80130);
	busquedasExistentesRango(recurso, Toolkit::BINARIO, 80180, 80190);

	//para chequear que funciona, creo uno, busco y lo elimino

	Toolkit::Alumno viejo(55566, 10015999, "En Recurso Viejo", Toolkit::BINARIO);
	recurso->guardarDato(viejo, Toolkit::ClaveAlumno(viejo.getPadron(),
			Toolkit::BINARIO));

	Toolkit::Alumno auxLectura(0, 0, "", Toolkit::BINARIO);
	bool encontrado = recurso->recuperarDato(Toolkit::ClaveAlumno(
			viejo.getPadron(), Toolkit::BINARIO), auxLectura);
	encontrado
	= ((encontrado) && (viejo.getNombre() == auxLectura.getNombre()));
	encontrado = ((encontrado) && ((viejo.getDNI()) == (auxLectura.getDNI())));

	recurso->eliminarDato(Toolkit::ClaveAlumno(viejo.getPadron(),
			Toolkit::BINARIO), auxLectura);
	encontrado
	= ((encontrado) && (viejo.getNombre() == auxLectura.getNombre()));
	encontrado = ((encontrado) && ((viejo.getDNI()) == (auxLectura.getDNI())));
	encontrado = ((encontrado)
			&& (!recurso->recuperarDato(Toolkit::ClaveAlumno(viejo.getPadron(),
					Toolkit::BINARIO), auxLectura)));

	if (encontrado)
	{
		cout << "Operaciones sobre el recuperado fueron satisfactorias" << endl;
	}
	else
	{
		cout << "ANDUVO MAL!! el recurso recuperado" << endl;
	}

	delete recurso;

}

void pruebaGeneralDelToolkit()
{
	creacionesErroneas();

	Toolkit::RecursoAlmacenamiento *recurso;
	recurso = nuevoDirecto();
	pruebaAux(recurso, "Buffer y Archivo", Toolkit::BINARIO);
	delete recurso;

	recurso = viejoRecurso(Toolkit::BINARIO);
	pruebaReconstruido(recurso, Toolkit::BINARIO);
	delete recurso;

	recurso = nuevoBuffer();
	pruebaAux(recurso, "Buffer", Toolkit::TEXTO);
	delete recurso;

	recurso = nuevoArchivo();
	pruebaAux(recurso, "Archivo", Toolkit::BINARIO);
	delete recurso;

	recurso = viejoRecurso(Toolkit::BINARIO);
	pruebaReconstruido(recurso, Toolkit::BINARIO);
	delete recurso;

	recurso = nuevoArchivoBSharpTexto();
	pruebaAux(recurso, "Archivo indexado B# con texto", Toolkit::TEXTO);

	Toolkit::ClaveAlumno clave(80001, Toolkit::TEXTO);
	Toolkit::Alumno dato(0, 0, "", Toolkit::TEXTO);

	recurso->bSharpGetSiguienteDato((Toolkit::Dato&)dato, (Toolkit::Clave&)clave);

	if(dato.getPadron() == 80002){
		cout << "Prueba B# get siguiente anda bien" << endl;
	} else {
		cout << "Prueba B# get siguiente: NO PASADA" << endl;
	}

	delete recurso;

	recurso = viejoRecurso(Toolkit::TEXTO);
	pruebaReconstruido(recurso, Toolkit::TEXTO);
	delete recurso;

	recurso = nuevoArchivoBSharpBinario();
	pruebaAux(recurso, "Archivo indexado B# con binario", Toolkit::BINARIO);
	delete recurso;

	recurso = viejoRecurso(Toolkit::BINARIO);
	pruebaReconstruido(recurso, Toolkit::BINARIO);
	delete recurso;

	recurso = nuevoDirecto();
	pruebaAux(recurso, "Escritura Directa", Toolkit::BINARIO);
	delete recurso;

	recurso = viejoRecurso(Toolkit::BINARIO);
	pruebaReconstruido(recurso, Toolkit::BINARIO);
	delete recurso;

	recurso = nuevoDiferidoBinario();
	pruebaAux(recurso, "Escritura Diferida con binario", Toolkit::BINARIO);
	delete recurso;

	recurso = viejoRecurso(Toolkit::BINARIO);
	pruebaReconstruido(recurso, Toolkit::BINARIO);
	delete recurso;

	recurso = nuevoDiferidoTexto();
	pruebaAux(recurso, "Escritura Diferida con texto", Toolkit::TEXTO);
	delete recurso;

	recurso = viejoRecurso(Toolkit::TEXTO);
	pruebaReconstruido(recurso, Toolkit::TEXTO);
	delete recurso;

	recurso = nuevoBloquesCompresos();
	pruebaAux(recurso, "Bloques compresos", Toolkit::BINARIO);
	delete recurso;

	recurso = viejoRecurso(Toolkit::BINARIO);
	pruebaReconstruido(recurso, Toolkit::BINARIO);
	delete recurso;

	cout << endl << "Terminaron las pruebas." << endl;

}

#endif /* PRUEBATOOLKIT_H_ */
